package com.yibo.user.service.user;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.yibo.redis.RedisCommand;
import com.yibo.support.helper.Assert;
import com.yibo.support.helper.JsonHelper;
import com.yibo.support.helper.ObjectHelper;
import com.yibo.support.helper.TimeHelper;
import com.yibo.support.inter.Command;
import com.yibo.support.jwt.JWTUtils;
import com.yibo.support.pojo.YBMessage;
import com.yibo.system.YBSystem;
import com.yibo.db.user.entity.LoginError;
import com.yibo.user.message.SendMsg;
import com.yibo.user.object.YBUser;
import com.yibo.db.user.mapper.loginerror.LoginErrorMapper;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;

import static com.yibo.support.constant.MsgConstant.LOGIN_ERROR_MORE;
import static com.yibo.support.constant.MsgConstant.LOGIN_TIMES_MORE;
import static com.yibo.support.constant.YBConstant.CLI_IP;
import static com.yibo.support.constant.YBConstant.TOKEN;
import static com.yibo.support.constant.YBConstant.*;
import static com.yibo.user.constant.Constant.*;

public abstract class BaseLoginCommand implements Command<YBUser> {

    /**
     * 返回值
     */
    protected YBUser result = new YBUser();


    protected String token;

    /**
     * ip地址
     */
    protected String ip;


    protected void  initIp(){
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            this.ip =  request.getHeader(CLI_IP)+"";
            this.token = request.getHeader(TOKEN);
        }catch (Exception e){
            //不抛出异常
        }
    }



    @Override
    public YBUser execute() {
        //校验登陆失败次数
        checkLoginFailed();

        //登陆
        YBUser ybUser =  login();

        //发送登陆消息
        sendMsg(ybUser);
        return ybUser;
    }

    private void sendMsg(YBUser ybUser) {
        YBMessage message = new YBMessage();
        message.setTitle("登陆提醒");
        message.setMessage("尊敬的"+ybUser.getUserName()+", 您于"+TimeHelper.getNow()+"登陆易博网！");
        message.setEmail(ybUser.getExtInfo().getEmail());
        getBean(SendMsg.class).send(message);
    }


    public abstract YBUser login();


    /**
     * 校验登陆ip 曾经登陆失败的次数
     */
    private  void  checkLoginFailed(){
        List<LoginError> errors = getBean(LoginErrorMapper.class).selectByMap(Collections.singletonMap(IP,this.ip));
        if(ObjectHelper.isEmpty(errors)){
            return;
        }

        LoginError error = errors.get(0);
        Assert.isTrue(LOGIN_ERROR_MORE,!checkSystemLoginConfig(error));
    }


    protected  boolean  checkSystemLoginConfig(LoginError loginError){
        int errorTimes = loginError.getLoginFailTimes();
        //如果还没有达到最大登陆失败次数，放行
        if(errorTimes < YBSystem.getLoginErrorTimes()){
            return true;
        }

        Timestamp timestamp = loginError.getEndLoginTime();
        //如果达到了，超过了时间，放行
        if(TimeHelper.time() - timestamp.getTime() >= YBSystem.getLoginErrorTimeOut()){
            getBean(LoginErrorMapper.class).deleteById(loginError.getUserId());
            return true;
        }
        return false;
    }


    /**
     * 添加到redis缓存中
     */
    protected void  addRedis(String userId){
        String newToken = JWTUtils.getInstance().getToken(userId);
        this.result.setToken(newToken);
        RedisCommand command = getBean(RedisCommand.class);
        command.set(YIBO_USER_REDIS_PREFIX_TOKEN +newToken,JsonHelper.toJson(this.result));
        command.set(YIBO_USER_REDIS_PREFIX_IP+ip,JsonHelper.toJson(this.result));
        command.set(YIBO_USER_REDIS_PREFIX_USER_ID+userId,JsonHelper.toJson(this.result));
    }


    protected YBUser checkRedisMsg(String userId){
        RedisCommand command = getBean(RedisCommand.class);
        YBUser user = null;
        if(!ObjectHelper.isEmpty(this.token)){
            user  = command.get(YIBO_USER_REDIS_PREFIX_TOKEN+this.token,YBUser.class);
        }
        if(user == null){
            boolean userIdDel = false;
            //删除IP redis用户信息
            user = command.remove(YIBO_USER_REDIS_PREFIX_IP+this.ip,YBUser.class);
            if(user == null) {
                userIdDel = true;
                user = command.remove(YIBO_USER_REDIS_PREFIX_USER_ID + userId,YBUser.class);
            }
            //删除token  redis信息
            if(user != null){
                command.remove(YIBO_USER_REDIS_PREFIX_TOKEN+user.getToken());
            }

            if(!userIdDel) {
                command.remove(YIBO_USER_REDIS_PREFIX_USER_ID + userId, YBUser.class);
            }
            //置空
            user = null;
        }
        return user;
    }


    /**
     * 校验是否登录次数过多
     */
    LoginError checkLoginError(){
        LoginErrorMapper errorMapper = getBean(LoginErrorMapper.class);
        LoginError error = errorMapper.selectList(new EntityWrapper<LoginError>().eq(IP,this.ip))
                .stream().findFirst().orElse(null);

        if(error != null){
            int times = error.getLoginFailTimes();
            Timestamp endTime = error.getEndLoginTime();
            Assert.isTrue(LOGIN_TIMES_MORE,times > YBSystem.getLoginErrorTimes()
                    && (System.currentTimeMillis() - endTime.getTime() < YBSystem.getLoginErrorTimeOut()));
        }
        return error;
    }

    void saveLoginError(LoginErrorMapper errorMapper,LoginError error,String userId){
        if(error == null) {
            error = new LoginError()
                    .setUserId(userId)
                    .setIp(this.ip)
                    .setEndLoginTime(TimeHelper.nowDate())
                    .setLoginFailTimes(1);
            errorMapper.insert(error);
        }else{
            error.setEndLoginTime(TimeHelper.nowDate())
                    .setLoginFailTimes(error.getLoginFailTimes()+1);
            errorMapper.updateById(error);
        }
    }
}
